#!/usr/bin/env guile
!#
;;; gui.scm --- Start GUI using Shepherd

;; Copyright © 2016 Alex Kost

;; Author: Alex Kost <alezost@gmail.com>
;; Created: 9 Feb 2016

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:

;; This script is a wrapper around 'herd' command to start X server,
;; window manager and other things on a free DISPLAY and virtual
;; terminal.
;;
;; My Shepherd config: <https://gitlab.com/alezost-config/shepherd>.

;;; Code:

(use-modules
 (srfi srfi-1)
 (srfi srfi-37)
 (al files)
 (al messages)
 (al display))


;;; Command-line args

(define (show-help)
  (format #t "Usage: ~a OPTION...
Start GUI on a free DISPLAY, using the following command:

  herd start gui:<DISPLAY> ...
"
           (car (command-line)))
  (display "
Options:
  -h, --help        display this help and exit
  -s, --simple      start only X server and terminal
  -t, --ssh-tty     update startup TTY for the started X display
  -n, --no-ssh-tty  do not update startup TTY for the started X display
")
  (display "
By default (without additional options), SSH (gpg-agent) startup TTY
will be updated for the started X display.  See description in the GnuPG
manual:

  (info \"(gnupg) Agent UPDATESTARTUPTTY\").

If '--simple' option is specified, default action is not updating SSH
TTY.  '--[no-]ssh-tty' option sets updating / not updating
uncoditionally.
"))

(define %default-options
  '((simple?     . #f)
    (update-tty? . undefined)))

(define %options
  (list
   (option '(#\h "help") #f #f
           (lambda _
             (show-help)
             (exit 0)))
   (option '(#\s "simple") #f #f
           (lambda (opt name arg seed)
             (alist-cons 'simple? #t
                         (alist-delete 'simple? seed eq?))))
   (option '(#\t "ssh-tty") #f #f
           (lambda (opt name arg seed)
             (alist-cons 'update-tty? #t
                         (alist-delete 'update-tty? seed eq?))))
   (option '(#\n "no-ssh-tty") #f #f
           (lambda (opt name arg seed)
             (alist-cons 'update-tty? #f
                         (alist-delete 'update-tty? seed eq?))))))

(define (parse-args args)
  "Return alist of options from command-line ARGS."
  (args-fold args %options
             (lambda (opt name arg seed)
               (print-error "Unrecognized option: '~a'" name)
               seed)
             (lambda (arg seed)
               (print-error "Useless argument: '~a'" arg)
               seed)
             %default-options))


;;; Main

(define* (start-gui display #:key simple?)
  "Run 'herd' command for starting GUI on DISPLAY."
  (apply system*
         "herd" "start" (string-append "gui" display)
         (if simple?
             '()
             (filter identity
                     (list "xterm"
                           (first-existing-program "stumpwm" "openbox")
                           "unclutter" "emacs")))))

(define (update-ssh-tty display)
  (setenv "DISPLAY" display)
  (system* "gpg-connect-agent" "updatestartuptty" "/bye"))

(define (main arg0 . args)
  (let* ((opts        (parse-args args))
         (simple?     (assoc-ref opts 'simple?))
         (update-tty? (assoc-ref opts 'update-tty?))
         (update-tty? (if (boolean? update-tty?)
                          update-tty?
                          (not simple?)))
         (display     (first-unused-display)))
    (start-gui display #:simple? simple?)
    (when update-tty? (update-ssh-tty display))))

(when (batch-mode?)
  (apply main (command-line)))

;;; gui.scm ends here
